package com.vip.mvc.utils.reflection;

import com.vip.mvc.annotation.Autowired;
import com.vip.mvc.annotation.Controller;
import com.vip.mvc.annotation.PathVariable;
import com.vip.mvc.annotation.RequestBody;
import com.vip.mvc.annotation.RequestMapping;
import com.vip.mvc.annotation.Service;
import com.vip.mvc.dispacher.RequestParam;
import com.vip.mvc.netty.NettyHttpRequestParam;
import com.vip.mvc.utils.JSONUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

/**
 * Created by cloudy.xie on 17/1/20.
 */
public class ReflectionUtils {
    private static org.slf4j.Logger logger = LoggerFactory.getLogger(ReflectionUtils.class);

    /**
     * 反射
     *
     */
    public static ClassReflection reflectionController(String beanName,Object obj)  {
        ClassReflection classReflection = null;
        try {
            classReflection = reflectionClass(obj,beanName);

            classReflection.setObj(obj);
            reflectionMethod(classReflection);

        } catch (ClassNotFoundException e) {
            logger.error("reflectionController-error",e);
        } catch (InstantiationException e) {
            logger.error("reflectionController-error",e);
        } catch (IllegalAccessException e) {
            logger.error("reflectionController-error",e);
        }

        return classReflection;
    }

//    public static ClassReflection reflectionService(String className)throws ClassNotFoundException {
//        ClassReflection classReflection = reflectionClass(className);
//
//        //获取所有的属性
//        Class c = Class.forName(className);
//        Field[] fs = c.getDeclaredFields();
//        return classReflection;
//    }

    public static Object invokeMethod(Method method,Object object,NettyHttpRequestParam request)
            throws InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException {
        Parameter[] parameters = method.getParameters();

        int len = 0;
        Object[] params;
        if(parameters!=null) {
            len = parameters.length;
        }

        if(len>0) {
            params = new Object[len];
            for (int i = 0; i < len; i++) {
                Parameter parameter = parameters[i];
                String type = parameter.getType().getName();
                if (parameter.isAnnotationPresent(PathVariable.class)) {
                    PathVariable pathVariable = (PathVariable) parameter.getDeclaredAnnotations()[0];
                    String paramName = request.getReqParamMap().get(pathVariable.value());
                    params[i] = getParamObj(type, paramName);
                } else if (parameter.isAnnotationPresent(RequestBody.class)) {
                    Class clazz = Class.forName(type);
                    params[i] = JSONUtils.fromJSON(request.getReqBody(), clazz);
                }
            }
        }else{
            params = new Object[0];
        }
        return method.invoke(object,params);
    }

//    public static Object invokeMethod(Method method,Object object){
//        return null;
//    }

    private static Object getParamObj(String type,String paramName){
        switch (type) {
            case "int":
            case "Integer":return paramName == null ?0 :Integer.parseInt(paramName);
            case "byte":
            case "Byte":return paramName == null ?0 :Byte.parseByte(paramName);
            case "short":
            case "Short":return paramName == null ?0 :Short.parseShort(paramName);
            case "long":
            case "Long":return paramName == null ?0 :Long.parseLong(paramName);
            case "float":
            case "Float":return paramName == null ?0 :Float.parseFloat(paramName);
            case "double":
            case "Double":return paramName == null ?0 :Double.parseDouble(paramName);
            default:return paramName;
        }
    }

    private static ClassReflection reflectionClass(Object obj,String beanName) throws ClassNotFoundException {
        ClassReflection classReflection = new ClassReflection();
        classReflection.setBeanName(beanName);
        Class c = obj.getClass();
        if(c.isAnnotationPresent(Controller.class)) {
            classReflection.setController(true);
        }else if(c.isAnnotationPresent(Service.class)){
            classReflection.setService(true);
        }
        return classReflection;
    }

    private static void reflectionMethod(ClassReflection classReflection) throws IllegalAccessException, InstantiationException {
        Object obj = classReflection.getObj();
        Method[] methodArr = obj.getClass().getMethods();
        if(methodArr == null || methodArr.length<=0){
            return;
        }

        for (Method method : methodArr){
            if(method.isAnnotationPresent(RequestMapping.class)){
                RequestParam requestMap = new RequestParam();

                Annotation[] annotations = method.getDeclaredAnnotations();
                for (Annotation annotation : annotations){
                    if(annotation.annotationType().equals(RequestMapping.class)){
                        RequestMapping requestMapping = (RequestMapping) annotation;

                        if(requestMapping.value() !=null && requestMapping.value().length>0) {
                            for (String url : requestMapping.value()) {
                                requestMap.setUrl(url);
                                requestMap.setRequestMethod(requestMapping.method());
                                requestMap.setMethod(method);
                                requestMap.setBeanName(classReflection.getBeanName());
                                requestMap.setObject(obj);
                                classReflection.addRequestMapList(requestMap);
                            }
                        }
                    }
                }
            }
        }
    }
}
